﻿enum Name
{

}

class TextView
{
    private _font: TextFont;
    private _cursors: TextCursor[];
    private _canvas: HTMLCanvasElement;
    private _wrapper: HTMLDivElement;
    private _context: CanvasRenderingContext2D;
    private _input: HTMLTextAreaElement;

    private _shiftPressed;
    private _ctrlPressed;

    delegate: ITextViewDelegate;
    textColor: string;
    selectionColor: string;
    backgroundColor: string;
    borderThickness: number;

    constructor()
    {
        this._font = new TextFont();
        this._cursors = [];
        this.textColor = "WindowText";
        this.selectionColor = "Highlight";
        this.backgroundColor = "Window";
        this.borderThickness = 2;
        this.delegate = null;
        this._createWrapper();
        this._createCanvas();
        this._context.font = this._font.getSize() + "px " + this._font.getFamily();
        this._createInput();
        this._createCursor(0, 0);
    }

    private _createCursor(line: number, ch: number): void
    {
        var cursor = new TextCursor(line, ch);
        cursor.textView = this;
        this._cursors.push(cursor);
    }

    private _insertTextAtCurrentPosition(text: string): void
    {
        for (var i = 0; i < this._cursors.length; i++)
        {
            var cursor: TextCursor = this._cursors[i];
            cursor.position = this.delegate.appendTextLinesAtPosition(text, cursor.position);
        }
        this._render();
    }
    private _deleteTextAtCurrentPosition(): void
    {
        for (var i = 0; i < this._cursors.length; i++)
        {
            var cursor: TextCursor = this._cursors[i];
            cursor.position = this.delegate.deleteTextWithRange(TextSelectionRange.withPoints(
                new TextPosition(cursor.position.line, cursor.position.character - 1),
                cursor.position));
        }
        this._render();
    }

    private _createWrapper(): void
    {
        this._wrapper = document.createElement("div");
        this._wrapper.style.display = "inline-block";
        this._wrapper.style.position = "relative";
        this._wrapper.style.backgroundColor = this.backgroundColor;
        this._wrapper.style.border = this.borderThickness + "px solid ";
        this._wrapper.style.overflow = "hidden";
        this._wrapper.tabIndex = 0;
        this._wrapper.addEventListener("focus", this._focus.bind(this), false);
        this._wrapper.addEventListener("keydown", this._addKeyModifier.bind(this), true);
        this._wrapper.addEventListener("keyup", this._removeKeyModfier.bind(this), true);
    }

    private _focus(): void
    {
        this._input.focus();
        this._render();
    }

    private _addKeyModifier(e: KeyboardEvent): any
    {
        switch (e.keyCode)
        {
            case 16:
                this._shiftPressed = true;
                break;
            case 17:
                this._shiftPressed = true;
                break;
        }
    }

    private _removeKeyModfier(e: KeyboardEvent): any
    {
        switch (e.keyCode)
        {
            case 16:
                this._shiftPressed = false;
                break;
            case 17:
                this._shiftPressed = false;
                break;
        }
    }

    private _clearModifidedKey(): void
    {
        this._shiftPressed = false;
        this._ctrlPressed = false;
    }

    private _createCanvas()
    {
        this._canvas = document.createElement("canvas");
        this._canvas.style.display = "block";
        this._context = this._canvas.getContext("2d");
        this.resize(640, 480);
        this._wrapper.appendChild(this._canvas);
        //   this.canvas.addEventListener("click", this.click.bind(this), false);
    }


    resize(width: number, height: number): void
    {
        this._canvas.width = width;
        this._canvas.height = height;
    }

    private _render(): void
    {
        var baselineOffset = this._font.getBaseline();
        var lineCount: number = this.delegate.lineCount();
        var lineHeight = this._font.getHeight();
        var maxHeight = Math.ceil(this._canvas.height / lineHeight);

        this._context.fillStyle = this.backgroundColor;
        this._context.fillRect(0, 0, this._canvas.width, this._canvas.height);
        this._context.fillStyle = this.textColor;

        if (lineCount < maxHeight)
            maxHeight = lineCount;

        for (var i = 0; i < maxHeight; ++i)
        {
            var topOffset = lineHeight * i;
            this._context.fillText(this.delegate.getLineText(i).slice(0), 0, topOffset + baselineOffset);
        }
    }

    private _createInput(): void
    {
        this._input = document.createElement("textarea");
        this._input.style.position = "absolute";
        this._input.style.top = "-25px";
        this._input.style.left = "-25px";
        this._input.style.height = "10px";
        this._input.style.width = "10px";
        this._input.addEventListener("input", this._handleInput.bind(this), false);
        this._input.addEventListener("keydown", this._keydown.bind(this), false);
        this._input.addEventListener("keypress", this._setInputText.bind(this, ""), false);
        this._input.tabIndex = -1;
        this._wrapper.appendChild(this._input);
    }

    private _keydown(e: KeyboardEvent)
    {
        var handled = true;
        switch (e.keyCode)
        {
            case 8: // Backspace
                this._deleteTextAtCurrentPosition();
                break;
            case 46: // Delete
                this._deleteTextAtCurrentPosition();
                break;
            case 13: // Enter
                this._insertTextAtCurrentPosition("\n");
                break;
            case 37: // Left arrow
                this._moveLeft();
                break;
            case 38: // Up arrow
                this._moveUp();
                break;
            case 39: // Right arrow
                this._moveRight();
                break;
            case 40: // Down arrow
                this._moveDown();
                break;
            default:
                handled = false;
        }
        if (handled)
            e.preventDefault();
    }
    private _handleInput(e: KeyboardEvent)
    {
        var target: HTMLTextAreaElement = <HTMLTextAreaElement>e.target;
        var value = target.value;
        this._insertTextAtCurrentPosition(value);
    }

    private _setInputText(text: string, force: boolean): void
    {
        this._input.value = text;
        this._input.selectionStart = 0;
        this._input.selectionEnd = text.length;
    }

    get view(): HTMLDivElement
    {
        return this._wrapper;
    }

    private _moveLeft(): void
    {
        for (var i = 0; i < this._cursors.length; i++)
        {
            var cursor: TextCursor = this._cursors[i];
            cursor.moveLeft();
        }
    }

    private _moveRight(): void
    {
        for (var i = 0; i < this._cursors.length; i++)
        {
            var cursor: TextCursor = this._cursors[i];
            cursor.moveRight();
        }
    }

    private _moveUp(): void
    {
        for (var i = 0; i < this._cursors.length; i++)
        {
            var cursor: TextCursor = this._cursors[i];
            cursor.moveUp();
        }
    }

    private _moveDown(): void
    {
        for (var i = 0; i < this._cursors.length; i++)
        {
            var cursor: TextCursor = this._cursors[i];
            cursor.moveDown();
        }
    }

    get font(): TextFont
    {
        return this._font;
    }

    get wrapper(): HTMLDivElement
    {
        return this._wrapper;
    }
}